package com.cloudcross.ssp.service.impl;

import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.adinall.dsp.core.data.KeyValueBeanOld;
import com.adinall.dsp.core.db.DBHelper;
import com.adinall.dsp.core.utils.NumberUtils;
import com.cloudcross.ssp.base.dao.GenericIBatisDao;
import com.cloudcross.ssp.common.Config;
import com.cloudcross.ssp.common.utils.DateUtil;
import com.cloudcross.ssp.common.utils.MapBuilder;
import com.cloudcross.ssp.common.utils.PropertiesUtils;
import com.cloudcross.ssp.model.RptAdxMedia;
import com.cloudcross.ssp.service.RptAdxMediaService;
import com.cloudcross.util.SqlServer;

/**
 * ADX媒体统计用Service
 * 
 * @author 高万超
 * @version V1.0.0 $ 2017年6月20日 下午6:39:35
 */
@Service
public class RptAdxMediaServiceImpl implements RptAdxMediaService {

    public static final String MAPPER = "rptAdxMediaSqlMapper";

    private static Logger logger = LogManager.getLogger(RptAdxMediaServiceImpl.class);

    @Autowired
    private GenericIBatisDao mapper;

    @Autowired
    private Config config;

    public void sync() {

        long start = System.currentTimeMillis();

        List<RptAdxMedia> result = pullData();

        update(result);

        logger.info("本次同步数据用时" + (System.currentTimeMillis() - start) + "ms");
    }

    private List<RptAdxMedia> pullData() {

        SqlServer pcServer = new SqlServer(config.getManageHost(), NumberUtils.parseInt(config.getManagePort()), config.getManageUser(),
                config.getManagePass(), config.getManageDbname(), 0);
        logger.info("创建了一个pc数据库链接");

        SqlServer appServer = new SqlServer(config.getAppHost(), NumberUtils.parseInt(config.getAppPort()), config.getAppUser(), config.getAppPass(),
                config.getAppDbname(), 0);
        logger.info("创建了一个app数据库链接");

        int day = NumberUtils.parseInt(PropertiesUtils.getProperty("/config.properties", "sync.adx.media.day"));

        Calendar c = Calendar.getInstance();
        c.add(Calendar.DAY_OF_YEAR, -day);

        String thatDay = DateUtil.getDate(DateUtil.DateFmts.YYYY_MM_DD, c.getTime());

        String sqlAppAdx = PropertiesUtils.getProperty("/sql-rpt-adx-media.properties", "sql.app.adx");
        sqlAppAdx = sqlAppAdx.replaceFirst("[?]", thatDay);

        String sqlApp = PropertiesUtils.getProperty("/sql-rpt-adx-media.properties", "sql.app");
        sqlApp = sqlApp.replaceFirst("[?]", thatDay);

        String sqlPc = PropertiesUtils.getProperty("/sql-rpt-adx-media.properties", "sql.pc");
        sqlPc = sqlPc.replaceFirst("[?]", thatDay);

        List<Future<List<RptAdxMedia>>> data = new ArrayList();

        ExecutorService pool = Executors.newFixedThreadPool(3, new ThreadFactory() {

            int threadIdx = 0;

            public Thread newThread(Runnable r) {
                return new Thread(r, "THREAD-PULL-ADX-MEDIA-" + threadIdx++);
            }
        });
        data.add(pool.submit(new Task(appServer, sqlAppAdx, "app-adx")));
        data.add(pool.submit(new Task(appServer, sqlApp, "app")));
        data.add(pool.submit(new Task(pcServer, sqlPc, "pc")));

        pool.shutdown();

        List<RptAdxMedia> result = new ArrayList<>();

        for (Future<List<RptAdxMedia>> f : data) {

            List<RptAdxMedia> tmp = null;
            try {
                tmp = f.get();
            } catch (Exception e) {
                logger.error(ExceptionUtils.getFullStackTrace(e));
            }

            if (tmp != null) {
                result.addAll(tmp);
            }
        }

        Timestamp now = new Timestamp(System.currentTimeMillis());
        for (RptAdxMedia bean : result) {
            bean.setSyncTime(now);
        }

        return result;
    }

    private void update(List<RptAdxMedia> result) {

        Set<String> dateSet = new TreeSet<>();

        for (RptAdxMedia bean : result) {
            dateSet.add(DateUtil.getDate(DateUtil.DateFmts.YYYY_MM_DD, bean.getDate()));
        }

        long start = System.currentTimeMillis();

        for (String date : dateSet) {
            mapper.delete(MAPPER + ".deleteByDate", date);
            logger.info("删除了这些数据:date = " + date);
        }
        logger.info("删除数据用时" + (System.currentTimeMillis() - start) + "ms");

        start = System.currentTimeMillis();
        for (List<RptAdxMedia> list : group(result)) {
            mapper.save(MAPPER + ".insertBatch", MapBuilder.create(HashMap.class).add("data", list).map());
        }
        logger.info("插入数据用时" + (System.currentTimeMillis() - start) + "ms,共计" + result.size() + "条数据");
    }

    private static <T> List<List<T>> group(List<T> data) {

        int size = data.size();

        int mode = 200;

        List<List<T>> result = new ArrayList<List<T>>(size / mode + 1);
        List<T> tmp = new ArrayList<T>(mode);

        for (int i = 0; i < data.size(); i++) {

            tmp.add(data.get(i));

            if (i != 0 && i % mode == 0) {
                result.add(tmp);
                tmp = new ArrayList<T>();
            }
        }

        if (!tmp.isEmpty()) {
            result.add(tmp);
        }

        return result;
    }

    private static class Task implements Callable<List<RptAdxMedia>> {

        private SqlServer server;
        private String sql;
        private String title;

        public Task(SqlServer server, String sql, String title) {
            this.server = server;
            this.sql = sql;
            this.title = title;
        }

        public List<RptAdxMedia> call() throws Exception {

            long start = System.currentTimeMillis();

            logger.info("正在远程查询:" + title + " -- > " + sql);

            ResultSet rs = server.select(sql);

            List<RptAdxMedia> data = DBHelper.mapping(rs, RptAdxMedia.class);
            logger.info("远程查询用时" + (System.currentTimeMillis() - start) + "ms, " + data.size() + "条数据 --> " + title);

            if (data == null || data.isEmpty()) {
                logger.warn("没有数据或查询失败:" + sql + " -- > " + sql);
            }

            return data;
        }
    }

    /**
     * 首页不需要了，暂时屏蔽，以后删除 ----20170802高万超
     */
    @Deprecated
    public List<KeyValueBeanOld> adxList() {
        return mapper.getList(MAPPER + ".adx");
    }
}
